package com.yunxin.yundubbo.handlers;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yunxin.yundubbo.enums.HandlerEnum;
import com.yunxin.yundubbo.interfaces.DubboHandler;
import com.yunxin.yundubbo.mode.Buffer;
import com.yunxin.yundubbo.mode.Message;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

@Slf4j
@Component
public class RequestHandler implements DubboHandler {

    @Resource
    private ApplicationContext context;

    @Override
    public void handler(ChannelHandlerContext ctx, Message message) {
        Channel channel = ctx.channel();

        try {
            // 1. 反序列化
            Buffer buffer = deserialization(message.getBytes(), Buffer.class);
            log.debug("Received request: {}", buffer);

            // 2. 获取目标类
            Class<?> targetClass = Class.forName(buffer.getClassName());

            // 3. 获取 Spring 容器里的实例
            Object bean = context.getBean(targetClass);
            if (bean == null) {
                throw new IllegalStateException("Bean not found for class: " + buffer.getClassName());
            }

            // 4. 找到对应方法
            Method targetMethod = findTargetMethod(targetClass, buffer.getMethod());
            if (targetMethod == null) {
                throw new NoSuchMethodException("Method " + buffer.getMethod() + " not found in class " + buffer.getClassName());
            }

            // 5. 准备参数
            Object[] args = prepareArgs(targetMethod, buffer.getData());

            // 6. 调用方法
            Object returnValue = targetMethod.invoke(bean, args);

            // 7. 返回结果
            String responseJson = returnValue != null ? JSON.toJSONString(returnValue) : "";
            send(message, buffer, responseJson, channel);

        } catch (ClassNotFoundException e) {
            log.error("Target class not found", e);
            sendError(message, "ClassNotFound: " + e.getMessage(), channel);
        } catch (NoSuchMethodException e) {
            log.error("Target method not found", e);
            sendError(message, "MethodNotFound: " + e.getMessage(), channel);
        } catch (InvocationTargetException e) {
            log.error("Error invoking target method", e.getTargetException());
            sendError(message, "InvocationError: " + e.getTargetException().getMessage(), channel);
        } catch (Exception e) {
            log.error("Unexpected error during request handling", e);
            sendError(message, "InternalError: " + e.getMessage(), channel);
        }
    }

    /** 查找指定方法 */
    private Method findTargetMethod(Class<?> targetClass, String methodName) {
        return Arrays.stream(targetClass.getMethods())
                .filter(m -> m.getName().equals(methodName))
                .findFirst()
                .orElse(null);
    }

    /** 准备方法调用参数 */
    private Object[] prepareArgs(Method method, String jsonData) {
        if (method.getParameterCount() == 0) {
            return new Object[0];
        }
        if (StrUtil.isEmpty(jsonData)) {
            throw new IllegalArgumentException("Method requires parameters but data is empty");
        }

        JSONObject json = JSON.parseObject(jsonData);
        Parameter[] parameters = method.getParameters();

        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            Object raw = json.get(param.getName());
            if (raw == null) {
                throw new IllegalArgumentException("Missing parameter: " + param.getName());
            }
            // 自动类型转换
            args[i] = JSON.parseObject(JSON.toJSONString(raw), param.getType());
        }
        return args;
    }

    /** 正常返回结果 */
    private static void send(Message message, Buffer buffer, String value, Channel channel) {
        buffer.setData(value);
        message.setBytes(JSON.toJSONString(buffer).getBytes());
        message.setLength(message.getBytes().length);
        channel.writeAndFlush(message);
    }

    /** 错误返回 */
    private static void sendError(Message message, String errorMsg, Channel channel) {
        Buffer errorBuffer = new Buffer();
        errorBuffer.setData(errorMsg);
        message.setBytes(JSON.toJSONString(errorBuffer).getBytes());
        message.setLength(message.getBytes().length);
        channel.writeAndFlush(message);
    }

    @Override
    public int getType() {
        return HandlerEnum.REQUEST.getType();
    }
}
